package com.bossly.metro.Activities;

import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;

import com.bossly.metro.CoreApplication;
import com.bossly.metro.Metropoliten;
import com.bossly.metro.PreferenceWrapper;
import com.bossly.metro.R;
import com.bossly.metro.StationsAdapter;
import com.bossly.metro.Views.MetroView;
import com.bossly.metro.Views.MetroView.StationSelectListener;
import com.bossly.metro.Views.SchemeView;
import com.bossly.metro.dom.City;
import com.bossly.metro.dom.Station;

public class MainActivity extends Activity implements OnClickListener,
		android.view.View.OnClickListener, LocationListener,
		StationSelectListener {
	private static final int FIND_LOCATION_TIME = 600000; // 60 seconds ( in
	// miliseconds )
	private static final int ACCURANCY = 1000; // 1 km
	private static final float GPS_ACCURANCY = 100; // 100 meters
	private static final int DIALOG_GPS = 12;
	private AutoCompleteTextView m_atvStart;
	private AutoCompleteTextView m_atvFinish;
	private Button m_searchButton;
	private int m_startStation = -1;
	private int m_finishStation = -1;
	private PreferenceWrapper m_prefs;
	private Station mStartStation;
	private Station mFinishStation;
	private LocationManager lm;
	private CoreApplication m_app;

	private boolean m_startpoint = false;
	private boolean m_endpoint = false;
	private boolean m_lock = false;

	private Location mStartLocation = null;
	private Location mFinishLocation = null;

	private MetroView mMapView;

	Button mHelpStart;
	Button mHelpFinish;
	private SchemeView mSchemeView;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.main);

		m_app = (CoreApplication) getApplication();

		m_prefs = new PreferenceWrapper(this);
		m_atvStart = (AutoCompleteTextView) findViewById(R.id.atvStart);
		m_atvFinish = (AutoCompleteTextView) findViewById(R.id.atvFinish);
		m_searchButton = (Button) findViewById(R.id.btnSearch);

		mHelpStart = (Button) findViewById(R.id.btnStartClear);
		mHelpStart.setOnClickListener(this);

		mHelpFinish = (Button) findViewById(R.id.btnFinishClear);
		mHelpFinish.setOnClickListener(this);

		mMapView = (MetroView) findViewById(R.id.mapView);
		mMapView.setOnStationClick(this);
		
		mSchemeView = (SchemeView)findViewById(R.id.schemeView);

		findViewById(R.id.btnStart).setOnClickListener(this);
		findViewById(R.id.btnFinish).setOnClickListener(this);
		m_searchButton.setOnClickListener(this);

		lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

		textChanged();
	}

	@Override
	protected void onResume() {
		m_startpoint = true;
		findLocation();

		// TODO Auto-generated method stub
		super.onResume();
	}

	@Override
	protected void onPause() {
		if (lm != null) {
			lm.removeUpdates(this);
		}

		// TODO Auto-generated method stub
		super.onPause();
	}

	private void textChanged() {
		m_atvStart.addTextChangedListener(new TextWatcher() {
			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
				if (s.length() > 0)
					mHelpStart.setBackgroundResource(R.drawable.clear_selector);
				else
					mHelpStart.setBackgroundResource(R.drawable.loc_selector);
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
				// TODO Auto-generated method stub

			}

			@Override
			public void afterTextChanged(Editable s) {
				if (!m_lock) {
					m_startStation = -1;
					mStartLocation = null;
					updateSearchButton();
				}
			}
		});

		m_atvStart.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(android.widget.AdapterView<?> adapter,
					View view, int position, long itemId) {
				// final String name = adapter.getAdapter().getItem( position
				// ).toString();
				m_startStation = (int) itemId;// m_database.getStationId(
												// m_app.getCity(), name );
				mStartLocation = null;

				updateSearchButton();
			};
		});

		m_atvFinish.addTextChangedListener(new TextWatcher() {

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
				if (s.length() > 0)
					mHelpFinish
							.setBackgroundResource(R.drawable.clear_selector);
				else
					mHelpFinish.setBackgroundResource(R.drawable.loc_selector);
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
				// TODO Auto-generated method stub

			}

			@Override
			public void afterTextChanged(Editable s) {
				if (!m_lock) {
					mFinishLocation = null;
					m_finishStation = -1;
					updateSearchButton();
				}
			}
		});

		m_atvFinish.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(android.widget.AdapterView<?> adapter,
					View view, int position, long itemId) {
				// final String name = adapter.getAdapter().getItem( position
				// ).toString();
				m_finishStation = (int) itemId;// m_database.getStationId(
												// m_app.getCity(), name );
				mFinishLocation = null;

				updateSearchButton();
			};
		});
	}

	private void loadLastStations() {
		if (!m_lock) {
			m_lock = true;

			Metropoliten metro = m_app.getMetropoliten();
			Station station;
			m_startStation = m_prefs.getStartStation();
			m_finishStation = m_prefs.getFinishStation();

			if (m_startStation >= 0) {
				station = metro.getStation(m_startStation);

				if (station != null)
					m_atvStart.setText(station.getName());
			}

			if (m_finishStation >= 0) {
				station = metro.getStation(m_finishStation);

				if (station != null)
					m_atvFinish.setText(station.getName());
			}

			updateSearchButton();
			m_lock = false;
		}
	}

	private void findLocation() {
		boolean bNetwork = lm
				.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
		boolean bGPS = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);

		if (bGPS) {
			Location l = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);

			if (l != null) {
				updateLocation(l);
			}

			bGPS = false;
			bNetwork = false;
			lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,
					FIND_LOCATION_TIME, GPS_ACCURANCY, this);
		} else {
			Toast t = Toast.makeText(this, R.string.gps_disable,
					Toast.LENGTH_LONG);
			t.setGravity(Gravity.CENTER, 0, 0);
			t.show();

			showDialog(DIALOG_GPS);

			if (bNetwork) {
				Location l = lm
						.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

				if (l != null) {
					updateLocation(l);
				}

				bGPS = false;
				bNetwork = false;
				lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
						FIND_LOCATION_TIME, ACCURANCY, this);
			}
		}

		int city = m_prefs.getSelectedCity();

		if (city < 0 && !bNetwork && !bGPS) {
			showDialog(R.id.menuCity);
		} else {
			updateTitle();
			updateSources();
			loadLastStations();
		}
	}

	@Override
	public void onLocationChanged(Location location) {
		updateLocation(location);
		lm.removeUpdates(this);
	}

	@Override
	public void onProviderDisabled(String provider) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onProviderEnabled(String provider) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
		// TODO Auto-generated method stub

	}

	private void updateLocation(Location location) {
		Station s = null;

		if (m_startpoint && !m_lock) {
			m_lock = true;
			s = m_app.getNearStation(location);

			if (s != null && m_startStation != s.getId()) {
				m_startStation = s.getId();
				m_atvStart.setText(s.getName());
				m_prefs.setStartStation(m_startStation);

				final Toast t = Toast.makeText(this,
						getString(R.string.near_station, s.getName()),
						Toast.LENGTH_LONG);
				t.setGravity(Gravity.CENTER, 0, 0);
				t.show();

				mStartLocation = new Location(location);
			}

			m_lock = false;
			m_startpoint = false;
		}

		if (m_endpoint && !m_lock) {
			m_lock = true;
			if (s == null)
				s = m_app.getNearStation(location);

			if (s != null && m_finishStation != s.getId()) {
				m_finishStation = s.getId();
				m_atvFinish.setText(s.getName());
				m_prefs.setFinishStation(m_finishStation);

				mFinishLocation = new Location(location);

				Toast t = Toast.makeText(this,
						getString(R.string.near_station, s.getName()),
						Toast.LENGTH_LONG);
				t.setGravity(Gravity.CENTER, 0, 0);
				t.show();
			}

			m_endpoint = false;
			m_lock = false;
		}

		updateSearchButton();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		getMenuInflater().inflate(R.menu.help, menu);

		// TODO Auto-generated method stub
		return super.onCreateOptionsMenu(menu);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menuCity:
			showDialog(R.id.menuCity);
			break;

		case R.id.menuPayment:
			startActivity(new Intent(this, PaymentActivity.class));
			break;
		}

		// TODO Auto-generated method stub
		return super.onOptionsItemSelected(item);
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		Dialog dlg;
		Builder builder;

		ArrayAdapter<City> cadapter;
		switch (id) {
		case R.id.menuCity:
			builder = new Builder(this);

			ArrayList<City> list = m_app.getCities();

			cadapter = new ArrayAdapter<City>(this,
					android.R.layout.simple_list_item_single_choice, list);
			builder.setSingleChoiceItems(cadapter, m_app.getCity() - 1, this);

			dlg = builder.create();
			break;

		case R.id.btnStart:
			builder = new Builder(this);
			builder.setTitle(R.string.start_station);

			final StationsAdapter adapter = new StationsAdapter(this, m_app);

			builder.setSingleChoiceItems(adapter, -1, new OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					if (!m_lock) {
						m_lock = true;

						mStartStation = m_app.getMetropoliten()
								.getStationByIndex(which);
						m_atvStart.setText(mStartStation.getName());
						m_startStation = mStartStation.getId();

						mStartLocation = null;
						updateSearchButton();

						m_lock = false;
					}

					dialog.dismiss();
				}
			});

			dlg = builder.create();
			break;

		case R.id.btnFinish:
			builder = new Builder(this);
			builder.setTitle(R.string.finish_station);

			final StationsAdapter adapterf = new StationsAdapter(this, m_app);

			builder.setSingleChoiceItems(adapterf, -1, new OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					if (!m_lock) {
						m_lock = true;

						mFinishStation = m_app.getMetropoliten()
								.getStationByIndex(which);
						m_atvFinish.setText(mFinishStation.getName());
						m_finishStation = mFinishStation.getId();

						mFinishLocation = null;
						updateSearchButton();

						m_lock = false;
					}

					dialog.dismiss();
				}
			});

			dlg = builder.create();
			break;

		case DIALOG_GPS:
			builder = new Builder(this);
			builder.setTitle(R.string.service_gps);
			builder.setMessage(R.string.gps_body);

			builder.setPositiveButton(R.string.gps_yes, new OnClickListener() {

				@Override
				public void onClick(DialogInterface dialog, int which) {
					/* bring up the GPS settings */
					Intent intent = new Intent(
							android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
					startActivity(intent);
				}
			});

			builder.setNegativeButton(R.string.gps_no, null);

			dlg = builder.create();
			break;

		default:
			dlg = super.onCreateDialog(id);
			break;
		}

		// TODO Auto-generated method stub
		return dlg;
	}

	@Override
	protected void onPrepareDialog(int id, Dialog dialog) {
		switch (id) {
		case R.id.menuCity:
			// do nothing
			break;

		case R.id.btnStart:
			AlertDialog d = (AlertDialog) dialog;
			StationsAdapter a = (StationsAdapter) d.getListView().getAdapter();
			a.refresh();
			break;

		case R.id.btnFinish:
			d = (AlertDialog) dialog;
			a = (StationsAdapter) d.getListView().getAdapter();
			a.refresh();
			break;

		default:
			super.onPrepareDialog(id, dialog);
			break;
		}

	}

	@Override
	public void onClick(DialogInterface dialog, int which) {
		dialog.dismiss();
		lm.removeUpdates(this);
		which++;

		if (m_app.getCity() != which) {
			m_app.changeCity(which);
			mMapView.setMetropolite(m_app.getMetropoliten());
			updateTitle();
		}

		if (!m_lock) {
			m_lock = true;
			updateSources();

			// clear fields
			m_atvStart.setText("");
			m_atvFinish.setText("");
			m_lock = false;
			updateSearchButton();
		}
	}

	private void updateTitle() {
		setTitle(getString(R.string.app_title, m_app.getCityName()));
		mMapView.setMap(m_app.getCity());
	}

	@Override
	public void onClick(View view) {
		switch (view.getId()) {
		case R.id.btnStart:
			showDialog(R.id.btnStart);
			break;

		case R.id.btnFinish:
			showDialog(R.id.btnFinish);
			break;

		case R.id.btnSearch:
			seachWay();
			break;

		case R.id.btnStartClear:
			mStartLocation = null;

			if (m_atvStart.getText().toString().length() > 0) {
				m_atvStart.setText("");
				m_prefs.setStartStation(-1);
			} else {
				m_startpoint = true;
				findLocation();
			}
			break;

		case R.id.btnFinishClear:
			mFinishLocation = null;

			if (m_atvFinish.getText().toString().length() > 0) {
				m_atvFinish.setText("");
				m_prefs.setFinishStation(-1);
			} else {
				m_endpoint = true;
				findLocation();
			}
			break;
		}
	}

	private void seachWay() {
		Intent intent = new Intent(this, DirectionActivity.class);

		intent.putExtra(DirectionActivity.STATION_START, m_startStation);
		intent.putExtra(DirectionActivity.STATION_FINISH, m_finishStation);

		if (mStartLocation != null) {
			intent.putExtra(DirectionActivity.START_LAT,
					mStartLocation.getLatitude());
			intent.putExtra(DirectionActivity.START_LNG,
					mStartLocation.getLongitude());
		}

		if (mFinishLocation != null) {
			intent.putExtra(DirectionActivity.FINISH_LAT,
					mFinishLocation.getLatitude());
			intent.putExtra(DirectionActivity.FINISH_LNG,
					mFinishLocation.getLongitude());
		}

		startActivity(intent);

		m_prefs.setStartStation(m_startStation);
		m_prefs.setFinishStation(m_finishStation);
	}

	private void updateSearchButton() {
		m_searchButton.setEnabled(m_startStation >= 0 && m_finishStation >= 0
				&& m_startStation != m_finishStation);
	}

	private void updateSources() {
		if (m_app.getCity() >= 0) {
			mMapView.setMetropolite(m_app.getMetropoliten());

			mSchemeView.m_metro = m_app.getMetropoliten();
			mSchemeView.invalidate();
			
			StationsAdapter adapter = new StationsAdapter(this, m_app);

			m_atvStart.setAdapter(adapter);
			m_atvFinish.setAdapter(adapter);
		}
	}

	@Override
	public void onStationSelected(Station station) {
		if (!m_lock) {
			m_lock = true;

			if (m_startStation < 0) {
				m_startStation = station.getId();
				m_atvStart.setText(station.getName());
			} else {
				m_finishStation = station.getId();
				m_atvFinish.setText(station.getName());
			}

			updateSearchButton();
			m_lock = false;
		}
	}
}